// Deploys a contract onto the specified network and generates
// transactions in batches to this contract
// Each transaction is submitted from a new account
// usage: node mockTransactions.js requestsPerBatch rpcEndpoint

const Web3 = require('web3');
const ethereumjs = require('ethereumjs-tx');
const wallet = require('ethereumjs-wallet');
const crypto = require('crypto');

const privLen = 40;
const rpc = process.argv[3];
const imei = '0x' + crypto.randomBytes(32).toString('hex');
const web3 = new Web3(new Web3.providers.HttpProvider(rpc));

var running = false;
var priv = '0x0000000000000000000000000000000000000000';
var rawTx = {
  chainId: 5,
  action: 2,
  nonce: 0,
  imei: imei,
  priv: priv,
};

function mockTx() {
  const account = wallet.generate();
  var _rawTx = Object.assign({}, rawTx, {action: 2});
  var _tx = new ethereumjs(_rawTx);
  _tx.sign(account.getPrivateKey());
  var _raw = '0x' + _tx['serialize']().toString('hex');
  web3.okey['sendRawTransaction'](_raw, (txErr, txHash) => {
    if (!txErr) {
      setInterval(batchRequests, 5000, account.getPrivateKey());
      console.log('Private Key: ', account.getPrivateKeyString());
      console.log('Address: ', account.getAddressString());
    } else {
      console.log('Error: ' + txErr);
    }
  });
}

function batchRequests(privateKey) {
  if (!running) {
    running = true;
    ethRequest(privateKey).then(() => running = false);
  }
}

function ethRequest(privateKey) {
  return new Promise((resolve, reject) => {
    rawTx.nonce += 1;
    rawTx.priv = hexIncrease(rawTx.priv)
    var tx = new ethereumjs(rawTx);
    tx.sign(privateKey);
    var raw = '0x' + tx['serialize']().toString('hex');
    web3.okey['sendRawTransaction'](raw, (txErr, txHash) => {
      if (!txErr) {
        resolve(txHash);
      } else {
        console.log('Error: ' + txErr);
        return reject('Error: ' + txErr);
      }
    });
  });
}

function hexIncrease(hex) {
  hex = web3.toHex(web3.toDecimal(hex) + 1).slice(2)
  if (hex.length < privLen) {
    hex = '0'.repeat(privLen - hex.length) + hex
  }
  if (hex.length > privLen) {
    hex = hex.slice(hex.length - privLen)
  }
  return '0x' + hex;
}

mockTx();